Skip to content

feat(container-indicator): add live performance, configuration, and terminal access - #511

Open
AndrewDi wants to merge 8 commits into
mactools-app:mainfrom
AndrewDi:feat/container-indicator-live-stats
Open

AndrewDi wants to merge 8 commits into
mactools-app:mainfrom
AndrewDi:feat/container-indicator-live-stats

Conversation

@AndrewDi

@AndrewDi AndrewDi commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Show live CPU, memory, and disk throughput for each running container, derived from two container stats samples, and chart the recent samples in the configuration window.
  • Add an ⓘ button that opens a frosted floating configuration window with the full container list configuration (resources, runtime, network, process, and environment variable names only).
  • Add one-click terminal access for running containers (container exec -it) and machines (container machine run -n), opened through a terminal chosen in settings.

Details

  • CPU percentage is relative to the container's configured cores, so 100% means the whole allotment is busy.
  • container stats --format json --no-stream is skipped entirely when nothing runs, avoiding its internal two-second sampling delay.
  • A failed stats read keeps the previous numbers visible and reports the failure; hiding the panel clears the sample baseline.
  • The controller retains up to 150 samples per running container (about twelve minutes at the five-second poll). Stopped containers lose their series, and pausing monitoring restarts it rather than bridging an unsampled gap.
  • The configuration window draws CPU, memory, and disk I/O as Swift Charts sparklines with hidden axes. Hovering a chart shows a rule, the nearest point, and that sample's time and value in place of the latest reading.
  • Terminal scripts are written as .command files in the user's temporary directory, validated before writing, and opened through LaunchServices.
  • The terminal picker lists the system default plus installed apps only, persists the choice, and prefers an installed tab-capable terminal. Ghostty and iTerm open a new tab through AppleScript; Terminal.app and other apps open a new window through their document handling.
  • The configuration window uses NSVisualEffectView glass with a transparent titlebar and is ordered above the menu-bar popover.
  • Environment values are masked in the configuration window because container list exposes secrets such as database passwords.

Validation

  • make test TEST_FILTER=ContainerIndicatorPluginTests — 44 tests passed.
  • make validate-changelog — passed.
  • make run — Debug app and plugin installed; live charts and hover readouts verified manually.

@AndrewDi

Copy link
Copy Markdown
Contributor Author

@ggbond268 PTAL

@ggbond2077

Copy link
Copy Markdown
Contributor

Thanks for adding these improvements! I reviewed 9d396cb2 and found two issues I recommend fixing before merging:

  1. Terminal launches can block interaction with the whole app. AppleScript execution and waiting for the external process currently happen synchronously on the main thread. A slow launch can delay input throughout MacTools, including other plugins. Please run the launch asynchronously with a timeout, and update the UI on the main thread when it finishes.

  2. The detail window can show stale readings as live data. When a stats read fails, it keeps the previous numbers and charts, but the error is only shown in the main panel. Please also show the failure and the last successful sample time in the detail window, clearly marking retained data as out of date.

Thanks again! These changes would make the new features more reliable.

@AndrewDi

Copy link
Copy Markdown
Contributor Author

Thanks for the review — both issues are fixed in a472fbb.

  1. Terminal launch no longer blocks the app. ContainerTerminalLaunching.launch is now async. The controller starts it from a main-actor task and only publishes the error when it finishes, so input in other plugins stays responsive. The default launcher runs /usr/bin/open and NSAppleScript on background queues and resumes after a 10-second timeout (terminating a still-running open process), so a stalled terminal cannot leave the action pending forever.
  2. Stale readings are marked in the detail window. When statsFailure is set, the live section now shows an orange banner with the failure message and the last successful sample time; the retained cards and charts stay visible but are explicitly labeled as out of date. The retained sample keeps its original sampledAt, covered by a test.

make test TEST_FILTER=ContainerIndicatorPluginTests — 44 tests passed.

@ggbond2077

Copy link
Copy Markdown
Contributor

Thanks for the update! I rechecked a472fbbe and confirmed that terminal launches no longer block app interaction. Two remaining cases still need a fix:

  1. The AppleScript timeout does not stop the launch. After 10 seconds, the caller reports failure, but the script keeps running. A slow launch may therefore complete after the error, and retrying could open duplicate tabs. Please run the script in a cancellable subprocess, such as osascript, and terminate and clean it up on timeout.

  2. Service-check failures can hide the stale-data warning. The detail window only checks statsFailure. If the service-status check fails, old readings remain visible while that warning disappears. Please also handle service-check failures in the detail window, keeping retained data marked as out of date with the last successful sample time until fresh data is available.

The 44 plugin tests pass, and I reproduced these cases with isolated diagnostics. Thanks again for the improvements!

@AndrewDi

Copy link
Copy Markdown
Contributor Author

Both remaining cases are addressed in d33e6ac.

  1. Timed-out AppleScript is now stopped. The script runs as an /usr/bin/osascript -e subprocess through the same timeout runner as /usr/bin/open. On timeout the process is terminated, then force-killed after two seconds if it ignores SIGTERM, so a reported failure cannot be followed by a late tab or a duplicate on retry. A new test verifies a hanging helper returns at the timeout instead of the helper's full runtime.
  2. Service-check failures keep the stale warning. The detail window now reads retainedDataWarning, which falls back to an inconclusive service check (status == .unknown) in addition to statsFailure. Retained cards and charts stay labeled out of date with the original sample time until a refresh succeeds. Added coverage for the inconclusive service-status path.

make test TEST_FILTER=ContainerIndicatorPluginTests — 46 tests passed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants